﻿using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Linq;
using System.Text;

namespace Faust.Andrew.MTG.Player.Shared
{
    [ServiceContract]
    [ServiceKnownType(typeof(CardAction))]
    [ServiceKnownType(typeof(GameStartAction))]
    [ServiceKnownType(typeof(MarkCardAction))]
    [ServiceKnownType(typeof(MoveCardAction))]
    [ServiceKnownType(typeof(NoAction))]
    [ServiceKnownType(typeof(NotificationAction))]
    [ServiceKnownType(typeof(Notification))]
    [ServiceKnownType(typeof(RefreshGameStateAction))]
    [ServiceKnownType(typeof(ShowCardsAction))]
    [ServiceKnownType(typeof(TransferControlAction))]
    [ServiceKnownType(typeof(UpdateCardAction))]
    [ServiceKnownType(typeof(UpdatePlayerAction))]
    [ServiceKnownType(typeof(RemoveTokenAction))]
    [ServiceKnownType(typeof(EndTurnAction))]
    [ServiceKnownType(typeof(PlanesWalkAction))]
    public interface IMTGServer
    {
        /// <summary>
        /// Join the game
        /// </summary>
        /// <param name="playerName">Name of the player. Must be unique to the game.</param>
        /// <param name="deck">The deck to be used in the game</param>
        /// <returns>targetPlayerID ID</returns>
        [OperationContract]
        int JoinGame(string playerName, Deck deck);        

        /// <summary>
        /// Join a game in progress
        /// </summary>
        /// <remarks>In case you had to restart the client for some reason such as a crash.</remarks>
        /// <param name="playerName">Name of the player. Must be the same name used when originally joining.</param>
        [OperationContract]
        int RejoinGame(string playerName);

        /*
        [OperationContract]
        void StartGame();

        [OperationContract]
        void EndGame();
        */

        /// <summary>
        /// Poll the server for any new actions needing to be performed
        /// </summary>
        /// <param name="targetPlayerID">Player requesting the update</param>
        [OperationContract]
        Queue<Action> Poll(int playerId);

        /// <summary>
        /// Send a message to one or more users
        /// </summary>
        /// <param name="playerID">Player sending the message</param>
        /// <param name="targetPlayerIDs">Player sending the message</param>
        /// <param name="message">message to send</param>        
        [OperationContract]
        void SendMessage(int playerId, List<int> targetPlayersIds, string message);

        /// <summary>
        /// Show Cards to one or more users
        /// </summary>
        /// <param name="playerID">Player Showing the cards</param>
        /// <param name="playersIDs">Players to show the cardIDs to</param>
        /// <param name="cardIDs">IDs of the cards to show.</param>        
        [OperationContract]
        void ShowCards(int playerID, List<int> targetPlayersIDs, List<int> cardIds);

        /// <summary>
        /// Send a notification to all users.
        /// </summary>
        /// <remarks>This is distinct from a message. A notification is an automatic notification based on some action being performed. Notifications are by definition system generated.</remarks>        
        /// <param name="playerId">Player sending the notification</param>
        [OperationContract]
        void Notify(int playerId, string message);

        /// <summary>
        /// Request a game refresh from the server.
        /// </summary>
        /// <remarks>
        /// This should only be called if the client thinks it has become out of sync. Even then it may not be necessary as the server will push out Game State refreshes regularly.
        /// Note: This method does not return the game state. Instead it adds the game state to the player's action queue.
        /// </remarks>
        /// <param name="playerId">Player requesting the refresh.</param>
        [OperationContract]
        void RefreshGameState(int playerId);

        /// <summary>
        /// Update the modifer text or counters on a cardID.
        /// </summary>
        /// <param name="cardID">New Version of cardID</param>
        /// <param name="playerId">Player Updating the card</param>
        /// <returns>Whether or not the update was successful</returns>
        [OperationContract]
        bool UpdateCard(int playerID, GameCard card);

        /// <summary>
        /// Mark or Unmark a cardID
        /// </summary>
        /// <param name="playerId">Player performing the mark</param>
        /// <param name="cardId">Card to Mark</param>        
        /// <returns>Whether or not the action was successful.</returns>
        [OperationContract]
        bool MarkCard(int playerId, int cardId, bool isMarked);

        /// <summary>
        /// Move a cardID to a new location.
        /// </summary>
        /// <param name="cardID">Card to Move</param>
        /// <param name="playerId">Player requesting the move</param>
        /// <param name="location">Location to move the card to</param>        
        /// <returns>Whether or not the move was successful</returns>
        [OperationContract]
        bool MoveCard(int playerId, int cardId, Location location);

        /// <summary>
        /// Transfer a card to the control of another player
        /// </summary>
        /// <param name="playerId">Player requesting the transfer</param>
        /// <param name="targetPlayerId">Player to transfer control to</param>        
        /// <param name="cardId">Card to transfer</param>        
        [OperationContract]
        bool TransferCard(int playerId, int targetPlayerId, int cardId);

        /// <summary>
        /// Updates a Player
        /// </summary>
        [OperationContract]
        bool UpdatePlayer(int playerId, Player player);

        [OperationContract]
        GameCard DrawCard(int playerId);

        [OperationContract]
        List<Shared.GameCard> DrawCards(int playerId, int count);

        [OperationContract]
        void PlayTokenCreature(int playerId, string tokenText, string imageKey, int quantity);

        [OperationContract]
        void RemoveTokenCreature(int playerId, int cardId);

        [OperationContract]
        bool ShuffleDeck(int playerId);

        [OperationContract]
        int RollDie(int playerId, int sides);

        [OperationContract]
        List<Shared.GameCard> GetCardList(int playerId, int targetPlayerId, Zone zone);

        [OperationContract]
        bool SendCardToDeck(int playerId, int cardId, Shared.DeckPosition deckPosition, int offset);

        [OperationContract]
        void EndTurn(int playerId);

        [OperationContract]
        void AttemptPlaneswalk(int playerId);

        [OperationContract]
        void RandomReveal(int playerId, int count, Shared.Zone sourceZone, List<int> targetPlayers);

        [OperationContract]
        void RandomDiscard(int playerId, int count, Shared.Zone sourceZone);
    }
}
